package cn.ms.neural;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import cn.ms.neural.engine.IEngine;
import cn.ms.neural.engine.core.EngineFactory;
import cn.ms.neural.entity.NeuralConf;
import cn.ms.neural.moduler.Moduler;
import cn.ms.neural.moduler.degrade.handler.IBizDegradeHandler;
import cn.ms.neural.moduler.degrade.handler.IDegradeHandler;
import cn.ms.neural.moduler.flowrate.handler.IFlowrateHandler;
import cn.ms.neural.moduler.idempotent.handler.IdempotentHandler;
import cn.ms.neural.moduler.passrate.IPassRate;
import cn.ms.neural.moduler.passrate.core.PassRateFactory;

/**
 * 中枢神经<br>
 * √ 1.放通率控制<br>
 * √ 2.流量控制<br>
 * √ 3.服务降级<br>
 * √ 4.幂等机制<br>
 * √ 5.超时控制<br>
 * √ 6.容错转移<br>
 * √ 7.线程池舱壁<br>
 * √ 8.线程隔离<br>
 * √ 9.慢性重试<br>
 * √ 10.MOCK服务<br>
 * 
 * @author lry
 *
 * @param <REQ>
 * @param <RES>
 */
public class Neural<REQ, RES> {

	public static final Logger logger = LogManager.getLogger(Neural.class);

	private Moduler<REQ, RES> moduler;
	/**
	 * 核心引擎
	 */
	private IEngine<REQ, RES> neuralEngine = new EngineFactory<REQ, RES>();

	public Neural(Moduler<REQ, RES> moduler) {
		this.moduler = moduler;
	}
	
	public RES neural(final NeuralConf conf, final IRoute<REQ, RES> route, REQ req) throws Throwable {
		return neural(conf, route, null, req);
	}

	public RES neural(final NeuralConf conf, final IRoute<REQ, RES> route,
			final IBizDegradeHandler<REQ, RES> bizDegradeHandler, REQ req) throws Throwable {
		// $NON-NLS-第一步:放通率校验$
		IPassRate passRate = new PassRateFactory(conf);
		passRate.passRate();// 拒绝放通,则直接向外抛异常

		// $NON-NLS-第二步:流量控制$
		RES flowrateRES = moduler.getFlowrate().flowrate(conf, req, new IFlowrateHandler<REQ, RES>() {
			/**
			 * 流量控制处理器 
			 */
			@Override
			public RES handler(NeuralConf flowrateConf, REQ flowrateREQ) throws Throwable {
				RES flowrateRES = null;

				if (logger.isInfoEnabled()) {
					logger.info("The Degrade msg is:{DegradeEnable[" + flowrateConf.isDegradeEnable() + "], DegradeType["
							+ flowrateConf.getDegradeType() + "], StrategyType[" + flowrateConf.getStrategyType() + "]}.");
				}

				// $NON-NLS-第三步:服务降级$
				flowrateRES = moduler.getDegrade().degrade(flowrateConf, flowrateREQ, bizDegradeHandler, new IDegradeHandler<REQ, RES>() {
					/**
					 * 服务降级处理器
					 */
					@Override
					public RES handler(NeuralConf degradeConf, REQ degradeREQ) throws Throwable {

						// $NON-NLS-第四步:幂等SLA$
						RES idempotentRES = moduler.getDempotent().idempotent(degradeConf, route, degradeREQ,new IdempotentHandler<REQ, RES>() {
							/**
							 * 幂等处理器
							 */
							@Override
							public RES handler(NeuralConf idempotentConf, IRoute<REQ, RES> idempotentRoute, REQ idempotentREQ) throws Throwable {
								// $NON-NLS-第五步:容错引擎$
								return neuralEngine.engine(idempotentConf, idempotentRoute, idempotentREQ);
							}
						});
						
						return idempotentRES;
					}
					
					@Override
					public RES mock(NeuralConf degradeConf, REQ degradeREQ) throws Throwable {
						return route.mock(degradeConf.getNeuralId(), degradeREQ);
					}
				});
				
				return flowrateRES;
			}
		});
		
		return flowrateRES;
	}

}
